package com.xzakota.minesweeper.controller;

import com.xzakota.minesweeper.Client;
import com.xzakota.minesweeper.log.XLogger;
import com.xzakota.minesweeper.model.GameModel;
import com.xzakota.minesweeper.model.entity.CellBean;
import com.xzakota.minesweeper.model.entity.LevelBean;
import com.xzakota.minesweeper.model.entity.RecordBean;
import com.xzakota.minesweeper.model.entity.UserBean;
import com.xzakota.minesweeper.ui.IWindow;
import com.xzakota.minesweeper.ui.dialog.CustomLevelDialog;
import com.xzakota.minesweeper.ui.dialog.GameOptionDialog;
import com.xzakota.minesweeper.ui.dialog.HelpDialog;
import com.xzakota.minesweeper.ui.dialog.HeroListDialog;
import com.xzakota.minesweeper.ui.dialog.templae.MessageDialog;

import java.awt.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 游戏控制器
 *
 * @author Xzakota
 */
@SuppressWarnings("unused")
public class Game {
    // 控制器实例
    private static Game GAME;
    // 模型
    public GameModel model;
    public GameRecords records;

    // 依附窗口
    private final IWindow attachWindow;

    // 监听器
    public LevelChangeListener levelChangeListener;
    public List<GameWinListener> gameWinListener = new ArrayList<>();
    public List<GameOverListener> gameOverListener = new ArrayList<>();

    public Game(IWindow attachWindow) {
        this.attachWindow = attachWindow;

        GAME = this;

        model = new GameModel();
        records = new GameRecords();
    }

    public static void dispatchEvent(String eventType, Object... args) {
        try {
            if (GAME == null) {
                throw new RuntimeException("Game not initialized");
            }

            Class<?>[] parameterTypes = new Class<?>[args.length];
            for (int i = 0; i < args.length; i++) {
                parameterTypes[i] = args[i].getClass();
            }
            Method method = Game.class.getDeclaredMethod(eventType, parameterTypes);
            method.invoke(GAME, args);
        } catch (Exception e) {
            XLogger.warn(e);
        }
    }

    public void newGame() {
        model.newGame();
    }

    public void setBasicLevel() {
        model.newGameWithGameLevel(LevelBean.LEVEL_BASIC);
        if (levelChangeListener != null) {
            levelChangeListener.levelChanged();
        }
    }

    public void setIntermediateLevel() {
        model.newGameWithGameLevel(LevelBean.LEVEL_INTERMEDIATE);
        if (levelChangeListener != null) {
            levelChangeListener.levelChanged();
        }
    }

    public void setExpenseLevel() {
        model.newGameWithGameLevel(LevelBean.LEVEL_EXPENSE);
        if (levelChangeListener != null) {
            levelChangeListener.levelChanged();
        }
    }

    public void markACell(CellBean cell) {
        model.markACell(cell);
    }

    public void willSweepACell(CellBean cell) {
        model.willSweepACell(cell);
    }

    public void sweepACell() {
        model.sweepACell();
    }

    public void sweepRoundCell() {
        model.sweepRoundCell();
    }

    public void willSweepRoundCell(CellBean cell) {
        model.willSweepRoundCell(cell);
    }

    public void toggleQuestionMarkEnable() {
        model.setQuestionMarkEnable(!model.isQuestionMarkEnable());
        model.setChanged();
    }

    public void toggleSoundEnable() {
        model.setSoundEnable(!model.isSoundEnable());
        model.setChanged();
    }

    public void toggleTheme() {
        model.setThemeType(0);

        CellBean[][] allCells = model.allCells;
        for (CellBean[] allCell : allCells) {
            for (CellBean mineCell : allCell) {
                mineCell.setChanged();
            }
        }
        model.setChanged();
    }

    public void exitingGame() {
        if (attachWindow != null && attachWindow.isShowing()) {
            attachWindow.closingWindow();
        }
    }

    public void exitGame() {
        model.exitGame();
        records.saveRecords();

        if (attachWindow != null && attachWindow.isShowing()) {
            attachWindow.closeWindow();
        }
    }

    public void showCustomLevelDialog() {
        new CustomLevelDialog().showWindow();
    }

    public void setCustomLevel(LevelBean customLevel) {
        model.newGameWithCustomLevel(customLevel);
        if (levelChangeListener != null) {
            levelChangeListener.levelChanged();
        }
    }

    public void showHeroListDialog() {
        HeroListDialog heroListDialog = new HeroListDialog();

        heroListDialog.updateView(this.records);
        heroListDialog.showWindow();
    }

    public void showHelpDialog() {
        new HelpDialog((Window) attachWindow).showWindow();
    }

    public void resetRecords() {
        records.resetRecords();
    }

    public void showAboutDialog() {
        new MessageDialog("关于", "这里暂时什么都没有").showWindow();
    }

    public void gameWin() {
        if (!gameWinListener.isEmpty()) {
            for (GameWinListener listener : gameWinListener) {
                listener.gameWin();
            }
        } else {
            new GameOptionDialog("你赢啦！").showWindow();

            LevelBean currentLevel = model.currentGameLevel;
            RecordBean oldRecord = records.getGameRecordByLevelID(currentLevel.id);
            if (model.playTime < oldRecord.playTime) {
                this.showRecordDialog();
            }
        }
    }

    public void gameOver() {
        if (!gameOverListener.isEmpty()) {
            for (GameOverListener listener : gameOverListener) {
                listener.gameOver();
            }
        } else {
            new GameOptionDialog("你输了，再接再厉").showWindow();
        }
    }

    public void saveGameTime(Integer time) {
        this.model.playTime = time;
    }

    public void saveNewRecord(String playerName) {
        RecordBean record = new RecordBean(model.currentGameLevel.id, playerName, model.playTime);
        records.saveNewRecord(record);
    }

    private void showRecordDialog() {
        MessageDialog dialog = new MessageDialog("你已破纪录");
        UserBean currentUser = Client.getClient().currentUser;
        if (currentUser != null) {
            saveNewRecord(currentUser.username);
        }
        dialog.setWindowClosingListener(e -> showHeroListDialog());
        dialog.setConfirmAction(e -> dialog.closingWindow());
        dialog.showWindow();
    }

    public interface LevelChangeListener {
        void levelChanged();
    }

    public interface GameWinListener {
        void gameWin();
    }

    public interface GameOverListener {
        void gameOver();
    }
}
